package org.demo.test.thread.lock;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;

public class MCSLock {

    private AtomicReference<MCSLock.Node> tail;

    private final ThreadLocal<MCSLock.Node> currentNode;

    private class Node{

        volatile boolean locked = true;

        AtomicReference<MCSLock.Node> next = new AtomicReference<>();
    }

    public MCSLock(){
        tail = new AtomicReference<>();
        // 初始化当前的CLH节点
        currentNode = new ThreadLocal();
    }

    public void lock(){
        MCSLock.Node curNode = currentNode.get();
        if(curNode == null){
            curNode = new MCSLock.Node();
            currentNode.set(curNode);
        }
        // 如果不为空，会存在重入问题需要解决


        MCSLock.Node predNode = tail.getAndSet(curNode);
        if(predNode != null){
            predNode.next.set(curNode);
            while (curNode.locked){

            }
        }
        println("获得锁.");
    }

    public void unlock() {
        MCSLock.Node curNode = currentNode.get();
        if(curNode == null){
            println("未曾获取过锁.");
        }
        println("释放锁001. \n\n");
        currentNode.remove();
        if(curNode.next.get() != null) {
            curNode.next.get().locked = false;
        }
//        println("释放锁002.");
//        currentNode.remove();
    }

    private void println(String msg){
        System.out.println(Thread.currentThread().getName()+"："+msg);
    }


    public static void main(String[] args) {
        final MCSLock clhLock = new MCSLock();
        CountDownLatch countDownLatch = new CountDownLatch(1);
        for(int i=0; i<10; i++){
            new Thread(()->{
                try {
                    countDownLatch.await();
                    clhLock.lock();
                    clhLock.println("do..........");
                    Thread.sleep(3000L);
                    clhLock.unlock();
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        countDownLatch.countDown();
    }
}
